﻿#region

using System;
using System.Collections.Generic;
using System.Linq;
using Tateeda.ClinicalStudy.Base.Data.DBModel;
using Tateeda.ClinicalStudy.Base.Data.EF;
using Tateeda.ClinicalStudy.Base.Modules.Common;
using Tateeda.ClinicalStudy.Base.Modules.Common.Extenstions;
using Tateeda.ClinicalStudy.Base.Modules.Infrastructure.Interfaces.Services;
using Tateeda.ClinicalStudy.Base.Modules.Models.Medication;
using Tateeda.ClinicalStudy.Base.Modules.Models.User;

#endregion

#region - Legal -

///<legal>
/// Copyright © 2011, Tateeda Media Network
/// All rights reserved. http://tateeda.com
///
/// Redistribution and use in source and binary forms, with or without
/// modification, are permitted provided that the following conditions
/// are met:
///
/// - Redistributions of source code must retain the above copyright
/// notice, this list of conditions and the following disclaimer.
///
/// - Neither the name of the Tateeda Media Network, nor the names of its
/// contributors may be used to endorse or promote products
/// derived from this software without specific prior written
/// permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
/// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
/// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
/// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
/// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
/// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING,
/// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
/// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
/// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
/// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
/// POSSIBILITY OF SUCH DAMAGE.
///</legal>

#endregion - Legal -

namespace Tateeda.ClinicalStudy.Base.Modules.Infrastructure.Concrete.Services {

    public class MedicationService : IMedicationService {
        private readonly SqlUnitOfWork _unitOfWork;

        public MedicationService() {
            _unitOfWork = new SqlUnitOfWork();
        }

        #region IMedicationService Members

        public virtual IUnitOfWork UnitOfWork {
            get { return _unitOfWork; }
        }

        public virtual int AddNewDrug(DrugModel drug) {
            UnitOfWork.Drugs.AddObject(drug.ToDrug());
            UnitOfWork.Commit();
            return drug.DrugId;
        }

        public virtual void AddNewDrugCategory(DrugCategoryModel drugCategoryModel) {
            UnitOfWork.DrugCategories.AddObject(drugCategoryModel.ToDrugCategory());
            UnitOfWork.Commit();
        }

        public virtual void AddNewDrugClass(DrugClassModel drugClassModel) {
            UnitOfWork.DrugClasses.AddObject(drugClassModel.ToDrugClass());
            UnitOfWork.Commit();
        }

        public virtual ICollection<SubjectDrugModel> AddSubjectDrug(SubjectDrugModel subjectDrug) {
            var sDrug = subjectDrug.ToSubjectDrug();

            UnitOfWork.SubjectDrugs.AddObject(sDrug);
            UnitOfWork.Commit();

            return
                UnitOfWork.SubjectDrugs.Where(sd => sd.SubjectId == subjectDrug.SubjectId && sd.IsBeforeStudy == false).
                    ToList().ToSubjectDrugModelList();
        }

        public virtual ICollection<SubjectDrugModel> AddSubjectMedicationHistory(SubjectDrugModel subjectDrug) {
            var sDrug = subjectDrug.ToSubjectDrug();

            UnitOfWork.SubjectDrugs.AddObject(sDrug);
            UnitOfWork.Commit();

            return
                UnitOfWork.SubjectDrugs.Where(sd => sd.SubjectId == subjectDrug.SubjectId && sd.IsBeforeStudy).ToList().
                    ToSubjectDrugModelList();
        }

        public virtual ICollection<RecreationalDrugOrSubstanceModel> AddSubstance(RecreationalDrugOrSubstanceModel substance) {
            var sub = substance.ToSubstance();
            UnitOfWork.RecreationalDrugOrSubstances.AddObject(sub);
            UnitOfWork.Commit();
            return
                UnitOfWork.RecreationalDrugOrSubstances.Where(s => s.SubjectId == substance.SubjectId).ToList().
                    ToSubstanceModelList();
        }

        public virtual void DeleteDrug(int drugId) {
            var drug = UnitOfWork.Drugs.Where(d => d.DrugId == drugId).SingleOrDefault();
            UnitOfWork.Drugs.DeleteObject(drug);
            UnitOfWork.Commit();
        }

        public virtual void DeleteDrugCategory(int drugCategoryId) {
            var drugCategory =
                UnitOfWork.DrugCategories.Where(d => d.DrugCategoryId == drugCategoryId).SingleOrDefault();
            UnitOfWork.DrugCategories.DeleteObject(drugCategory);
            UnitOfWork.Commit();
        }

        public virtual void DeleteDrugClass(int drugClassId) {
            var drugClass = UnitOfWork.DrugClasses.Where(d => d.DrugClassId == drugClassId).SingleOrDefault();
            UnitOfWork.DrugClasses.DeleteObject(drugClass);
            UnitOfWork.Commit();
        }

        public virtual void DeleteSubjectDrug(int subjectDrugId) {
            var sDrug = UnitOfWork.SubjectDrugs.Where(sd => sd.SubjectDrugId == subjectDrugId).FirstOrDefault();
            UnitOfWork.SubjectDrugs.DeleteObject(sDrug);
            UnitOfWork.Commit();
        }

        public virtual void DeleteSubstance(int subjstanceId) {
            var sub =
                UnitOfWork.RecreationalDrugOrSubstances.Where(s => s.RecreationalDrugOrSubstanceId == subjstanceId).
                    SingleOrDefault();
            UnitOfWork.RecreationalDrugOrSubstances.DeleteObject(sub);
            UnitOfWork.Commit();
        }

        public virtual ICollection<SubjectDrugModel> EditSubjectsDrug(SubjectDrugModel subjectDrug) {
            var sDrug =
                UnitOfWork.SubjectDrugs.Where(sd => sd.SubjectDrugId == subjectDrug.SubjectDrugId).FirstOrDefault();
            if (sDrug != null) {
                sDrug.UpdatedOn = subjectDrug.UpdatedOn;
                sDrug.Dosage = subjectDrug.Dosage;
                sDrug.IsCurrent = subjectDrug.IsCurrent;
            }

            UnitOfWork.Commit();
            ICollection<SubjectDrugModel> drugs =
                UnitOfWork.SubjectDrugs.Where(sd => sd.SubjectId == subjectDrug.SubjectId).ToList().
                    ToSubjectDrugModelList();
            return drugs;
        }

        public virtual void EditSubstance(RecreationalDrugOrSubstanceModel substance) {
            //We have to get all the values from DB first and then overwrite with parameter data
            var sub =
                UnitOfWork.RecreationalDrugOrSubstances.Where(
                    s => s.RecreationalDrugOrSubstanceId == substance.RecreationalDrugOrSubstanceId).SingleOrDefault();
            sub = substance.ToSubstance();
            UnitOfWork.Commit();
        }

        public virtual DrugModel FindDrugByName(string drugName) {
            return UnitOfWork.Drugs.Where(d => d.Name.Equals(drugName)).SingleOrDefault().ToDrugModel();
        }

        public virtual ICollection<DrugModel> FindNonPsychoDrugsByName(string drugName) {
            return
                UnitOfWork.Drugs.Where(
                    d => d.Name.StartsWith(drugName) && d.DrugClassId == Constants.DefaultNonPsychotropicClass).ToList()
                    .ToDrugModelList();
        }

        public virtual DrugModel GetDrug(int drugId) {
            return UnitOfWork.Drugs.Where(d => d.DrugId == drugId).SingleOrDefault().ToDrugModel();
        }

        public virtual ICollection<DrugCategoryModel> GetDrugCategories() {
            return UnitOfWork.DrugCategories.ToList().ToDrugCategoryModelList();
        }

        public virtual DrugCategoryModel GetDrugCategory(int categoryId) {
            return
                UnitOfWork.DrugCategories.Where(dc => dc.DrugCategoryId == categoryId).FirstOrDefault().
                    ToDrugCategoryModel();
        }

        public virtual DrugClassModel GetDrugClass(int drugClassId) {
            return UnitOfWork.DrugClasses.Where(dc => dc.DrugClassId == drugClassId).FirstOrDefault().ToDrugClassModel();
        }

        public ICollection<DrugClassModel> GetDrugClasses(int categoryId) {
            return UnitOfWork.DrugClasses.Where(dc => dc.DrugCategoryId == categoryId).ToList().ToDrugClassModelList();
        }

        public virtual ICollection<DrugClassModel> GetDrugClassesForCategory(int categoryId) {
            return UnitOfWork.DrugClasses.Where(dc => dc.DrugCategoryId == categoryId).ToList().ToDrugClassModelList();
        }

        public virtual ICollection<DrugModel> GetDrugsByClass(int classId, ref int totalCoutn, int pageIndex = 0,
                                                       int pageSize = 20) {
            totalCoutn = UnitOfWork.Drugs.Where(dc => dc.DrugClassId == classId).Count();
            return
                UnitOfWork.Drugs.Where(dc => dc.DrugClassId == classId).OrderBy(dr => dr.SortOrder).Skip(pageIndex).Take
                    (pageSize).ToList().ToDrugModelList();
        }

        public ICollection<DrugModel> GetDrugsByClass(int classId) {
            int cnt = 0;
            return GetDrugsByClass(classId, ref cnt, 0, 200);
        }

        public virtual ICollection<SubjectModel> GetSubjectsForDurg(int drugId) {
            var subjects = from subj in UnitOfWork.Subjects
                           join sd in UnitOfWork.SubjectDrugs
                               on subj.SubjectId equals sd.SubjectId
                           where sd.DrugId == drugId
                           orderby subj.SortOrder
                           select subj;
            return subjects.ToList().ToSubjectModelList();
        }

        public virtual ICollection<RecreationalDrugOrSubstanceModel> GetSubjectSubstancesPerAppointment(int subjectId,
                                                                                                 int appointementId) {
            return
                UnitOfWork.RecreationalDrugOrSubstances.Where(
                    d => d.SubjectId == subjectId && d.AppointementId == appointementId).ToList().ToSubstanceModelList();
        }

        public virtual ICollection<RecreationalDrugOrSubstanceModel> GetSubstances(int subjectId) {
            return
                UnitOfWork.RecreationalDrugOrSubstances.Where(s => s.SubjectId == subjectId).ToList().
                    ToSubstanceModelList();
        }

        public virtual ICollection<SubjectDrugModel> StopPrescriptionDrug(int subjectDrugId, DateTime stopDate) {
            var sDrug = UnitOfWork.SubjectDrugs.Where(sd => sd.SubjectDrugId == subjectDrugId).FirstOrDefault();
            if (sDrug != null) {
                sDrug.UpdatedOn = DateTime.UtcNow;
                sDrug.IsStopped = true;
                sDrug.IsChanged = true;
                sDrug.IsCurrent = false;
                sDrug.EndDate = stopDate;
            }
            UnitOfWork.Commit();
            return
                UnitOfWork.SubjectDrugs.Where(sd => sDrug != null && sd.SubjectId == sDrug.SubjectId).ToList().
                    ToSubjectDrugModelList();
        }

        public SubjectDrugModel GetSubjectsDrug(int subjectDrugId) {
            return
                UnitOfWork.SubjectDrugs.Where(sd => sd.SubjectDrugId == subjectDrugId).SingleOrDefault().
                    ToSubjectDrugModel();
        }

        public void EditDrugName(int drugId, string name) {
            UnitOfWork.LazyLoadingOn = false;
            var drug = UnitOfWork.Drugs.Where(d => d.DrugId == drugId).FirstOrDefault();
            if (drug != null) {
                drug.Name = name;
                drug.UpdatedOn = DateTime.UtcNow;
            }
            UnitOfWork.Commit();
            UnitOfWork.LazyLoadingOn = true;
        }

        #endregion
    }
}